﻿using System;
using System.Linq;
using System.Collections.Generic;

namespace WpfAi.Protocol
{
    public abstract class BaseProtocol : IProtocol
    {
        protected abstract int CommandID { get; }
        protected virtual List<byte> Data { get; } = new List<byte> { 0x01 };
        protected byte[] GetHeader(int dataLength, int seq)
        {
            //////////命令头(12字节)/////////
            byte[] h = new byte[10];
            h[0] = 0xA5;
            h[1] = 0xA5;
            ////////////////两个命令字节+数据长度///////
            var udataLength = (ushort)(2 + dataLength);
            h[6] = (byte)(0xff & udataLength);
            h[7] = (byte)((0xff00 & udataLength) >> 8);


            var uSeq = (ushort)seq;
            h[8] = (byte)(0xff & uSeq);
            h[9] = (byte)((0xff00 & uSeq) >> 8);

            var resCrc = new byte[2];
            Crc16(h, ref resCrc);
            Array.Reverse(resCrc);
            byte[] header = new byte[12];
            Array.Copy(h, header, h.Length);
            header[10] = resCrc[0];
            header[11] = resCrc[1];
            return header;
        }
        /// <summary>
        /// 接口实现
        /// </summary>
        /// <returns></returns>
        public virtual byte[] GetByte(List<byte> data = null)
        {
            return this.GetByteByDataLength(data == null ? this.Data : data);
        }
        /// <summary>
        /// 获取数据
        /// </summary>
        /// <returns></returns>
        private byte[] GetByteByDataLength(List<byte> data)
        {
            var header = GetHeader(data == null ? 0 : data.Count, 1);
            var h = header.ToList();
            AddCommand(ref h);
            AddData(ref h, data);
            WarpCrc(ref h);
            return h.ToArray();
        }
        /// <summary>
        /// 添加命令
        /// </summary>
        /// <param name="l"></param>
        private void AddCommand(ref List<byte> l)
        {
            l.Add((byte)(CommandID & 0xff));
            l.Add((byte)((CommandID >> 8) & 0xff));
        }
        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="l"></param>
        protected virtual void AddData(ref List<byte> l, List<byte> data)
        {
            if (null != data)
                l.AddRange(data);
        }
        /// <summary>
        /// 计算报文CRC
        /// </summary>
        public void WarpCrc(ref List<byte> l)
        {
            var resCrc = new byte[2];
            Crc16(l.ToArray(), ref resCrc);
            Array.Reverse(resCrc);

            l.Add(resCrc[0]);
            l.Add(resCrc[1]);
        }
        /// <summary>
        /// Crc运算公式
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="ResCRC16"></param>
        /// <returns></returns>
        public bool Crc16(byte[] buffer, ref byte[] ResCRC16)
        {
            bool status = false;
            ushort crc = 0xFFFF;
            int size = buffer.Length;
            int i = 0;
            if (size > 0)
            {
                while (size-- > 0)
                {
                    crc = (ushort)((crc >> 8) | (crc << 8));
                    crc ^= buffer[i++];
                    crc ^= (ushort)(((byte)crc) >> 4);
                    crc ^= (ushort)(crc << 12);
                    crc ^= (ushort)((crc & 0xff) << 5);
                }
            }
            if (ResCRC16[0] == (byte)((crc >> 8) & 0xff) && ResCRC16[1] == (byte)(crc & 0xff))
            {
                status = true;
            }
            ResCRC16[1] = (byte)(crc & 0xff);
            ResCRC16[0] = (byte)((crc >> 8) & 0xff);
            return status;
        }
    }
}
